package com.sinodata.bsm.center.expression;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import bsh.Interpreter;

/**
 * 
 * <p>
 * Description: 表达式运算与解析类
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-11-30 14:36:13      liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class Expressions {

    private static Logger logger = Logger.getLogger(Expressions.class);

    private static Interpreter interpreter;

    private static Interpreter tester;

    private static Pattern propPattern;

    private static Pattern attrPattern;

    private static Pattern incPattern;

    private static Pattern tpropPattern;

    static {
        interpreter = new Interpreter();
        InputStreamReader reader = null;
        try {
            reader = new InputStreamReader(Expressions.class.getResourceAsStream("functions.bsh"));
            interpreter.eval(reader);
        } catch (Exception e) {
            logger.error("fail to initial expression function libraries ", e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    logger.error("fail to close InputStreamReader ", e);
                }
            }
        }

        propPattern = Pattern.compile("prop\\((\\d+,\\d+)[L|l]?\\)");
        attrPattern = Pattern.compile("attr\\((\\d+,\\d+)\\)");
        incPattern = Pattern.compile("inc\\((\\d+,\\d+)[L|l]?,\\d+\\)");
        tpropPattern = Pattern.compile(".*tprop\\((\\d+,\\d+)[L|l]?,(\\S+)\\)");//表格类型事件界面判断表达式
    }

    /**
     * 进行表达式运算
     *
     * @param expr
     * @return
     * @throws Exception
     */
    public static Object eval(String expr) throws Exception {
        if (expr == null) {
            return null;
        }
        Object o = null;
        try {
            o = interpreter.eval(expr);
        } catch (Exception e) {
            logger.error("failed to call Expressions.eval() ", e);
            throw e;
        }
        return o;
    }

    public synchronized static Object eval(String expr, Map<String, Object> variables) throws Exception {
        if (expr == null) {
            return null;
        }
        for (String varName : variables.keySet()) {
            Object varValue = variables.get(varName);
            if (varValue != null) {
                interpreter.set(varName, varValue);
            }
        }
        Object o = null;
        try {
            o = interpreter.eval(expr);
        } catch (Exception e) {
            logger.error("failed to call Expressions.eval( " + expr + ")");
            throw e;
        }
        return o;
    }

    /**
     * 表达式进行测试
     * 
     * @param expr
     * @throws Exception
     */
    public synchronized static Object test(String expr) throws Exception {
        Object o = null;
        if (tester == null) {
            tester = new Interpreter();
            InputStreamReader reader = null;
            try {
                reader = new InputStreamReader(Expressions.class.getResourceAsStream("functions.bsh"));
                tester.eval(reader);
            } catch (Exception e) {
                logger.error("fail to initial expression function libraries ", e);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        logger.error("fail to close the InputStream ", e);
                    }
                }
            }
        }
        if (expr == null) {
            return null;
        }
        o = tester.eval(expr);
        //String string = "";
        return o;
    }

    /**
     * 解析表达式中使用的资源指标，数据返回的格式 List<resId,propId> 例如:[60,30, 30,10]
     *
     * @param expr
     * @return
     */
    public static List<String> parsePropNodes(String expr) {
        List<String> nodes = new ArrayList<String>();
        nodes.addAll(parseNodes(propPattern, expr));
        nodes.addAll(parseNodes(incPattern, expr));
        nodes.addAll(parseNodes(tpropPattern, expr));
        return nodes;
    }

    /**
     * 解析表达式中使用的资源属性，数据返回的格式 List<resId,attrId> 例如:[60,30, 30,10]
     *
     * @param expr
     * @return
     */
    public static List<String> parseAttrNodes(String expr) {
        return parseNodes(attrPattern, expr);
    }

    /**
     * 判断能否匹配到表格表达式
     * 
     * @param expr
     * @return
     */
    public static List<String> parseTableExpr(String expr) {
        return parseNodes(tpropPattern, expr);
    }

    /**
     * 按正则表达式解析表达式
     *
     * @param pattern
     * @param expr
     * @return
     */
    public static List<String> parseNodes(Pattern pattern, String expr) {
        List<String> nodes = new ArrayList<String>();
        Matcher matcher = pattern.matcher(expr);
        while (matcher.find()) {
            nodes.add(matcher.group(1));
        }
        return nodes;
    }

    /**
     * main函数用来测试
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //        String exp = "1+$1";
        //        Map var = new HashMap();
        //        var.put("$1", 2L);
        //        System.out.println(eval(exp, var));
        //        Pattern incPattern = Pattern.compile("inc\\((\\d+,\\d+)[L|l]?,\\d+\\)");
        //        String expr = "(inc(322323,120201060000003L,6)*100)>-1";
        //        List<String> nodes = new ArrayList<String>();
        //        Matcher matcher = incPattern.matcher(expr);
        //        while (matcher.find()) {
        //            nodes.add(matcher.group(1));
        //        }
        //        for (String str : nodes) {
        //            System.out.println(str);
        //        }
        String expr = "round(3.00)<2";

        System.out.println(Expressions.test(expr));
    }
}
